package com.zbkj.service.service.ai;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.zbkj.common.config.CrmebConfig;
import com.zbkj.common.constants.Constants;
import com.zbkj.common.exception.CrmebException;
import com.zbkj.common.model.system.SystemAttachment;
import com.zbkj.common.model.user.User;
import com.zbkj.common.utils.CrmebUtil;
import com.zbkj.common.utils.RestTemplateUtil;
import com.zbkj.service.service.ai.constants.AiConstants;
import com.zbkj.service.service.ai.enums.AiPhgConfigEnum;
import com.zbkj.service.service.ai.request.AiHairstyleMaterialsCallbackRequest;
import com.zbkj.service.service.ai.request.AiHairstyleMaterialsRequest;
import com.zbkj.service.service.ai.response.AiHairestyleMaterialsAddAiMaterialsResponse;
import com.zbkj.service.service.ai.utils.Base64ToMultipartFile;
import com.zbkj.service.service.ai.utils.UniToStrUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;
import com.zbkj.service.service.publics.attachment.SystemAttachmentService;
import com.zbkj.service.service.config.SystemConfigService;
import com.zbkj.service.service.user.UserService;
import com.zbkj.common.redis.RedisUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * ai人像发型合成-service接口-实现类
 * @author lijie
 */
@Log4j2
@Service
public class AiProtraitHairstyleGenerateServiceImpl implements AiProtraitHairstyleGenerateService {

    @Autowired
    private SystemAttachmentService systemAttachmentService;

    @Autowired
    private CrmebConfig crmebConfig;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private RestTemplateUtil restTemplateUtil;

    @Autowired
    private UserService userService;

    @Override
    public JSONObject getAiHairParamJson(int attid, String base64) {
        //定义设置json参数-调用ai接口：目标注册提取特征接口
        JSONObject json = new JSONObject();
        json.put("userid","0");
        json.put("name",String.valueOf(attid));
        json.put("image", base64);
        json.put("token","isning");
        String api = systemConfigService.getValueByKeyException(AiPhgConfigEnum.ai_api_hmfe_callback.name());
        json.put("asyncPath",api);
        log.info(String.valueOf(json));
        return json;
    }

    @Override
    public AiHairestyleMaterialsAddAiMaterialsResponse addAiMaterials(AiHairstyleMaterialsRequest request) {
        //定义统计变量
        int total = request.getAttIds().size(); //总数
        int success = 0; //成功多少个
        int fail = 0; //失败多少个

        //得到pid
        String pid = systemAttachmentService.getConfigPid(AiPhgConfigEnum.ai_attid_pid_hm.name());

        //查询素材-循环处理
        log.info(String.valueOf(request));
        List<SystemAttachment> attachmentList = systemAttachmentService.listByIds(request.getAttIds());
        for (SystemAttachment attachment:attachmentList) {
            //保存素材-到指定分类
            SystemAttachment aiNew = new SystemAttachment();
            BeanUtils.copyProperties(attachment,aiNew);
            aiNew.setPid(Integer.valueOf(pid));
            aiNew.setName(CrmebUtil.getUuid());
            systemAttachmentService.save(aiNew);
            log.info(String.valueOf(aiNew));

            //得到图片域名
            String imgPrefix = systemConfigService.getValueByKey(Constants.UPLOAD_LOCAL_URL);;
            String imgUrl = new StringBuffer()
                    .append(imgPrefix)
                    .append("/")
                    .append(aiNew.getSattDir())
                    .toString();
            log.info(imgUrl);

            //转base64
            String base64 = Base64ToMultipartFile.convertImageToBase64(imgUrl);
            JSONObject json = this.getAiHairParamJson(aiNew.getAttId(), base64);
            log.info(String.valueOf(json));

            //发起请求
            String ai_api = this.getAiServerUrl(AiPhgConfigEnum.ai_api_hmfe.name());
            String reslut = restTemplateUtil.postStringData(ai_api,json.toString());
            log.info(reslut);
            JSONObject resJson = new JSONObject(reslut);
            String code = resJson.getStr("code");
            if("200".equals(code)){
                success++;
            }else{
                fail++;
                //失败删除
                systemAttachmentService.removeById(aiNew.getAttId());
            }
        }

        //返回
        AiHairestyleMaterialsAddAiMaterialsResponse response= new AiHairestyleMaterialsAddAiMaterialsResponse();
        response.setTotal(total);
        response.setFail(fail);
        response.setSuccess(success);
        return response;
    }

    @Override
    public Boolean callbackAiHm(AiHairstyleMaterialsCallbackRequest request) {
        try{
            //得到图片信息
            this.callbackPublicYw(request);
            return Boolean.TRUE;
        }catch (Exception e){
            e.printStackTrace();
            throw new CrmebException(e.getMessage());
        }
    }

    @Override
    public Boolean step3GenerateValidate(String attidPH) {
        //从缓存里取-第2步人像特征提取的attid-图片信息
        SystemAttachment attachment_PH = redisUtil.get(AiConstants.callback_result_aiphg +":" + attidPH);
        log.info(String.valueOf(attachment_PH));
        if(null == attachment_PH) {
            log.info("redis-没有找到-第2步人像特征提取图片信息！");
            return Boolean.FALSE;
        }else {
            return Boolean.TRUE;
        }
    }

    @Override
    public SystemAttachment step3Generate(String attidPH, String attidHM) {
        try{
            //得到用户
            User user = userService.getInfoException();

            //从缓存里取-第2步人像特征提取的attid-图片信息
            SystemAttachment attachment_PH = systemAttachmentService.getById(attidPH);
            log.info(String.valueOf(attachment_PH));
            if(null == attachment_PH) {
                throw new CrmebException("第2步选择的人像attid错误！！");
            }

            //读取-发型素材
            SystemAttachment attachment_HM = systemAttachmentService.getById(attidHM);
            if(null == attachment_HM){
                throw new CrmebException("发型素材attid错误！！");
            }

            //转为base64图片数据
            String front_api_url = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_FRONT_API_URL);
            log.info(front_api_url);
            String base64Img_PH = Base64ToMultipartFile.convertImageToBase64(new StringBuffer()
                            .append(front_api_url)
                            .append("/")
                            .append(attachment_PH.getSattDir()).toString());
            String base64Img_HM = Base64ToMultipartFile.convertImageToBase64(new StringBuffer()
                    .append(front_api_url)
                    .append("/")
                    .append(attachment_HM.getSattDir()).toString());

            //设置请求-ai合成人像发型图-参数
            JSONObject json = new JSONObject();
            json.put("userid",String.valueOf(user.getUid()));
            json.put("src_name",String.valueOf(attachment_PH.getAttId()));
            json.put("src_image",base64Img_PH);
            json.put("ref_name",String.valueOf(attachment_HM.getAttId()));
            json.put("ref_image",base64Img_HM);
            json.put("token","isning");

            //发送请求得到结果
            String ai_api = this.getAiServerUrl(AiPhgConfigEnum.ai_api_step3Generate.name());
            String reslut = restTemplateUtil.postStringData(ai_api,json.toString());
            JSONObject jsonResult = this.reslutToJsonObject(reslut);
            String code = jsonResult.getStr("code");
            if ("200".equals(code)){
                String data = jsonResult.getStr("data");
                JSONObject resData = new JSONObject(data);
                String image = resData.getStr("image");

                //保存-合成的人脸发型图
                SystemAttachment attachment = systemAttachmentService.base64ImgSaveLocalhost(
                        image,
                        crmebConfig.getImagePath(),
                        CrmebUtil.getUuid());
                //设置用户
                attachment.setUserId(String.valueOf(user.getUid()));
                //指定分类
                String pid = systemAttachmentService.getConfigPid(AiPhgConfigEnum.ai_attid_pid_hecheng.name());
                Integer pidInt = Integer.valueOf(pid);
                attachment.setPid(pidInt);
                systemAttachmentService.save(attachment);

                //扣除用户积分-扣除1个 operationIntegral(user.getUid(), request.getIntegralValue(), user.getIntegral(), "sub");
                userService.operationIntegral(user.getUid(),1,user.getIntegral(),"sub");

                //返回-合成图
                return attachment;
            }else{
                throw new CrmebException("ai应答："+jsonResult.getStr("msg"));
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new CrmebException(e.getMessage());
        }
    }

    @Override
    public Boolean step2Callback(AiHairstyleMaterialsCallbackRequest request) {
        try{
            //得到图片信息
            SystemAttachment attachment = this.callbackPublicYw(request);
            //放入缓存
            String redisKey = AiConstants.callback_result_aiphg +":"+ attachment.getAttId();
            redisUtil.set(redisKey, attachment);
            return Boolean.TRUE;
        }catch (Exception e){
            e.printStackTrace();
            throw new CrmebException(e.getMessage());
        }
    }

    @Override
    public Boolean step2ExtractFeature(Integer attid) {
        try {
            //读取-人像图片并转为base64
            SystemAttachment attachment = systemAttachmentService.getById(attid);
            if (attachment == null) {
                throw new CrmebException("人像图片attid错误！");
            }

            //转为base64
            String front_api_url = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_FRONT_API_URL);
            String imgPath = new StringBuffer(front_api_url).append("/").append(attachment.getSattDir()).toString();
            log.info(imgPath);
            String multipartBase64 = Base64ToMultipartFile.convertImageToBase64(imgPath);
            log.info(String.valueOf(attachment));

            //设置请求-ai提取特征接口-参数
            JSONObject json = this.geStep2EfParamJson(attachment.getAttId(), multipartBase64);
            String ai_api = this.getAiServerUrl(AiPhgConfigEnum.ai_api_step2ExtractFeature.name());
            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
            //设置链接超时-1分钟
            factory.setConnectTimeout(60000);
            //设置读取超时-1分钟
            factory.setReadTimeout(60000);
            RestTemplate restTemplate = new RestTemplate(factory);
            HttpHeaders headers = new HttpHeaders();
            headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.add("Accept", MediaType.APPLICATION_JSON.toString());
            HttpEntity<String> requestEntity = new HttpEntity<>(json.toString(), headers);
            String reslut = restTemplate.postForEntity(ai_api, requestEntity, String.class).getBody();

            //String reslut = restTemplateUtil.postStringData(ai_api,json.toString());  //后续优化 线程池里
            log.info(reslut);
            JSONObject resJson = new JSONObject(reslut);
            if ("200".equals(String.valueOf(resJson.get("code")))) {
                return Boolean.TRUE;
            } else {
                throw new CrmebException("ai" + resJson.get("msg"));
            }
        }catch (ResourceAccessException e){
            e.printStackTrace();
            throw new CrmebException("ai服务超时或服务已停止!");
        }
    }

    /**
     * 第2步-请求ai接口json参数封装
     * @param attid                 用于特征提取的人像attid
     * @param multipartBase64       转换后的base格式
     * @return
     */
    private JSONObject geStep2EfParamJson(int attid, String multipartBase64) {
        JSONObject json = new JSONObject();
        json.put("userid",String.valueOf(userService.getUserIdException()));
        json.put("name",String.valueOf(attid));
        json.put("image", multipartBase64);
        json.put("token","isning");
        String ai_api_callback = systemConfigService.getValueByKeyException(AiPhgConfigEnum.ai_api_step2ExtractFeature_callback.name());
        json.put("asyncPath",ai_api_callback);
        log.info(String.valueOf(json));
        return json;
    }

    @Override
    public List<SystemAttachment> step1Prune(MultipartFile multipart) {
        try {
            //验证非空
            if (multipart == null || multipart.isEmpty()) {
                throw new RuntimeException("图片不能为空！");
            }

            //得到用户-验证余额
            User user = userService.getInfoException();
            int integral = Optional.ofNullable(user.getIntegral()).orElse(0);
            if(1 > integral){
                throw new CrmebException("积分余额不足！请充值！");
            }

            //转为-字节码和base64
            byte[] imageBytes = multipart.getBytes();
            BASE64Encoder base64Encoder = new BASE64Encoder();
            String base64EncoderImg = base64Encoder.encode(imageBytes);
            //去掉特殊字符
            String base64 = base64EncoderImg.replaceAll("[\\s*\t\n\r]", "");

            //base64图片-放入list
            List<String> listImg = new ArrayList<>();
            listImg.add(base64);

            //定义请求json参数
            JSONObject jsonParam = new JSONObject();
            jsonParam.put("id",String.valueOf(user.getUid()));
            jsonParam.put("images",listImg);
            jsonParam.put("token","isning");

            //调用请求
            String ai_api = this.getAiServerUrl(AiPhgConfigEnum.ai_api_step1Prune.name());
            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
            //设置链接超时-1分钟
            factory.setConnectTimeout(60000);
            //设置读取超时-1分钟
            factory.setReadTimeout(60000);
            RestTemplate restTemplate = new RestTemplate(factory);
            HttpHeaders headers = new HttpHeaders();
            headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.add("Accept", MediaType.APPLICATION_JSON.toString());
            HttpEntity<String> requestEntity = new HttpEntity<>(jsonParam.toString(), headers);
            String reslut = restTemplate.postForEntity(ai_api, requestEntity, String.class).getBody();
            //String reslut = restTemplateUtil.postStringData(ai_api,jsonParam.toString());
            JSONObject jsonResult = this.reslutToJsonObject(reslut);
            log.info(String.valueOf(jsonResult));
            JSONArray imageBase64Array = jsonResult.getJSONObject("data").getJSONArray("images");
            log.info(String.valueOf(imageBase64Array));

            //得到pid
            String pid = systemAttachmentService.getConfigPid(AiPhgConfigEnum.ai_attid_pid_prune.name());
            Integer pidInt = Integer.valueOf(pid);

            //循环处理-剪裁的人像
            List<SystemAttachment> list =new ArrayList<>();
            for (int i=0;i<imageBase64Array.size();i++) {
                //保存到本地
                String imageBase64 = imageBase64Array.getStr(i);
                SystemAttachment attachment = systemAttachmentService.base64ImgSaveLocalhost(
                        imageBase64,
                        crmebConfig.getImagePath(),
                        CrmebUtil.getUuid());
                //设置用户
                attachment.setUserId(String.valueOf(user.getUid()));
                //设置指定分类
                attachment.setPid(pidInt);
                //保存到数据库
                systemAttachmentService.save(attachment);

                //添加到集合
                list.add(attachment);
            }

            //返回-人像剪裁列表
            return list;
        } catch (ResourceAccessException re){
             re.printStackTrace();
             throw new CrmebException("ai服务异常！可能是因为超时、服务已停止等原因！请稍后重试！");
        } catch (IOException e) {
            e.printStackTrace();
            throw new CrmebException("发生错误:"+e.getMessage());
        }
    }

    @Override
    public String getAiServerUrl(String configKey) {
        String check = systemConfigService.getValueByKeyException(AiPhgConfigEnum.ai_api_server_check.name());
        String api_;
        if("1".equals(check)){
            api_ = systemConfigService.getValueByKeyException(AiPhgConfigEnum.ai_api_prefix.name());
        }else{
            api_ = systemConfigService.getValueByKeyException(AiPhgConfigEnum.ai_api_prefix_server.name());
        }
        String configValue = systemConfigService.getValueByKeyException(configKey);
        return new StringBuffer()
                .append(api_)
                .append(configValue)
                .toString();
    }

    /**
     * ai返回的json字符串转JSONObject对象
     * @param reslut
     * @return
     */
    private JSONObject reslutToJsonObject(String reslut) {
        log.info(reslut);
        reslut = UniToStrUtil.unicodeToString(reslut);
        reslut = StringEscapeUtils.unescapeJava(reslut); //将字符串去除转义
        int s = reslut.indexOf("{");
        reslut = reslut.substring(s); //截取字符串
        JSONObject jsonResult = new JSONObject(reslut.trim());
        return jsonResult;
    }

    /**
     * ai回调公共业务
     * @param request
     * @return
     * @throws IOException
     */
    private SystemAttachment callbackPublicYw(AiHairstyleMaterialsCallbackRequest request) throws IOException {
        //查询
        SystemAttachment attachment = systemAttachmentService.getById(request.getName());
        log.info(String.valueOf(attachment));
        if(null == attachment) {
            throw new CrmebException("没有找到素材！");
        }

        //保存到本地
        SystemAttachment attVo = systemAttachmentService.base64ImgSaveLocalhost(
                request.getImage(),
                crmebConfig.getImagePath(),
                attachment.getAttId().toString());

        //更新素材地址
        attachment.setSattDir(attVo.getSattDir());
        systemAttachmentService.updateById(attachment);
        return attachment;
    }
}
